#!/usr/bin/perl

# This is mymemcalc, a program for generating basic performance 
# statistics for memcache pools. 
#
# This program is copyright (c) 2008 Ryan Lowe.
# Feedback and improvements are welcome (ryan.a.lowe@gmail.com)
#
# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, version 2; OR the Perl Artistic License.  On UNIX and similar
# systems, you can issue `man perlgpl' or `man perlartistic' to read these
# licenses.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place, Suite 330, Boston, MA  02111-1307  USA.

use strict;
use warnings FATAL => 'all';
use Pod::Usage;
use Getopt::Long qw ( :config no_ignore_case bundling );
use English qw ( -no_match_vars );
use XML::Simple;
use Cache::Memcached;

my $PROGRAM  = 'mymemcalc';
my $VERSION  = '0.0.2';
my $WEBSITE  = 'http://www.pablowe.net/mymemcalc/';
my $CODESITE = 'http://code.google.com/p/mymemcalc';

################################################################################
# Get configuration information, setting sane defaults
################################################################################

my %options;

my $gop = new Getopt::Long::Parser;

if ( !$gop->getoptions (
  'config=s'       => \$options { 'config' },
  'help|?'         => \$options { 'help' },
  'print-defaults' => \$options { 'defaults' },
  'quiet|Q'        => \$options { 'quiet' },
  'version|V'      => \$options { 'version' } ) ) {

  pod2usage ( 2 );

}

################################################################################
# Die when necessary, then set sane defaults
################################################################################

pod2usage ( 2 ) if ( $#ARGV eq -1 );

pod2usage ( 2 ) if ( $options { 'help' } );

if ( $options { 'version' } ) {

  print $PROGRAM . ' ' . $VERSION .
        ' (Check for updates at: ' . $WEBSITE . ")\n";
  exit;

}

$options { 'config' } = '/etc/mymemcalc.cnf' if ( !$options { 'config' } );

$options { 'pool' } = $ARGV [ $#ARGV ];

if ( $options { 'defaults' } ) {

  print "$PROGRAM defaults are:

ATTRIBUTE                  VALUE
-------------------------- ------------------
config                     /etc/mymemcalc.cnf
help                       FALSE
print-defaults             FALSE
quiet                      FALSE 
version                    FALSE
";

  exit;

}

# READ CONFIG FILE
my $xml = XML::Simple->new() or die "Could not create a new XML::Simple";
my $config;
eval { $config = $xml->XMLin ( $options { 'config' } ); };

if ($@) {

  print 'Config file (' . $options { 'config' } .
        ") does not exist ... exiting\n";
  exit(2);

}

# Make sure the specified pool is valid
if ( !exists $config->{ 'pool' }{ $options { 'pool' } } ) {

  die ( 'Invalid Pool: ' . $options { 'pool' } . "\n" );

}

my %hash_config = %{ $config->{ 'pool' }{ $options { 'pool' } } };

################################################################################
# Begin the main program
################################################################################

# Set up the memcache pool
my @mp;

foreach my $host ( keys %{ $hash_config{ 'host' } } ) {

  push(@mp,$host . ':' . $hash_config{ 'host' }{ $host }->{ 'port' });

}

my $mcache = new Cache::Memcached();
$mcache->set_servers(\@mp);

# Get the stats
my %stats=();
%stats = %{$mcache->stats('misc')};

# Memcache Hit Ratio
my $hits   = $stats{'total'}->{'get_hits'};
my $misses = $stats{'total'}->{'get_misses'};
my $total  = $hits + $misses;

print 'Statistics For: ' . $options { 'pool' } . "\n";

print '  Memcache Hit Ratio: ' . substr( ( ( $hits / $total ) * 100 ), 0, 5 ) . "%\n";

if ( !$options { 'quiet' } ) {

  print '    Total Hits:       ' . $hits . "\n";
  print '    Total Misses:     ' . $misses . "\n";

}

# Calculate Memcache Fill Ratio
my $total_bytes = 0;
my $used_bytes  = 0;

foreach my $host ( keys %{ $stats{ 'hosts' } } ) {

  $total_bytes += $stats { 'hosts' }{ $host }{ 'misc' }->{ 'limit_maxbytes' };
  $used_bytes  += $stats { 'hosts' }{ $host }{ 'misc' }->{ 'bytes' };

}

print '  Memcache Fill Ratio: ' . substr( ( ( $used_bytes / $total_bytes ) * 100 ), 0, 5 ) . "%\n";

if ( !$options { 'quiet' } ) {

  print '    Total Bytes: ' . $total_bytes . "\n";
  print '    Used Bytes:  ' . $used_bytes . "\n";

}

=pod

=head1 NAME

mymemcalc - Basic reporting on Memcached Hit Rates for memcached servers

=head1 SYNOPSIS

 mymemcalc [options] pool

 Options:
   --config=<full_path_to_file> The config file to use
   --help                       Display this help and exit.
   --print-defaults             Print the program argument list and exit.
   --quiet                      Do not output total set/get numbers.
   --version                    Output version information and exit.
   pool                         The pool (as defined in the config file)
                                for which to calculate statistics

 defaults are:

 ATTRIBUTE                  VALUE
 -------------------------- ------------------
 config                     /etc/mymemcalc.cnf
 help                       FALSE
 print-defaults             FALSE
 quiet                      FALSE
 version                    FALSE

=head1 DESCRIPTION

mymemcalc is a command-line utility for basic reporting on 
Memcached Hit Rates for groups of memcached servers.

=head1 SYSTEM REQUIREMENTS

mymemcalc 0.0.2, requires the following Perl modules:

  Pod::Usage
  GetOpt::Long
  XML::Simple
  Cache::Memcached

=head1 BUGS

Please report all bugs and feature requests to L<$WEBSITE>.

=head1 LICENSE

This program is copyright (c) 2008 Ryan Lowe.
Feedback and improvements are welcome (ryan.a.lowe@gmail.com).

THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, version 2; OR the Perl Artistic License.  On UNIX and similar
systems, you can issue `man perlgpl' or `man perlartistic' to read these
licenses.

You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA  02111-1307  USA.

=head1 AUTHOR

Ryan Lowe (ryan.a.lowe@gmail.com)

=head1 VERSION

This manual page documents 0.0.2 of mymemcalc.

=cut

